#include "Wed_phy_yt8512h.h"

/**
 * \brief PHY YT8512 ID 检查
 *
 * @param p_phy    PHY 设备名字
 * @param phy_addr PHY 设备地址
 *
 * @return 成功返回 0
 */
int Wed_phy_yt8512h_id_chk(struct Wed_phy *p_phy, int phy_addr){
    int      ret;
    uint16_t data = 0;
    uint32_t phy_id;

    if (p_phy == NULL) {
        return -WED_EINVAL;
    }

    /* 读 PHY 设备 ID */
    ret = p_phy->p_opts->p_fn_mdio_read(p_phy->p_opts_arg, phy_addr, GEN_PHY_ID1_REG, &data);
    if (ret != 0) {
        return ret;
    }
    phy_id = (data << 16);

    ret = p_phy->p_opts->p_fn_mdio_read(p_phy->p_opts_arg, phy_addr, GEN_PHY_ID2_REG, &data);
    if (ret != 0) {
        return ret;
    }
    phy_id |= data;

    if (phy_id != YT8512H_ID) {
        return -WED_ENOSUPPORT;
    }
    return 0;
}

/**
 * \brief PHY YT8512 链接灯设置
 *
 * @param p_phy    PHY 设备名字
 * @param phy_addr PHY 设备地址
 * @param led_idx  灯索引
 *
 * @return 成功返回 0
 */
int Wed_phy_yt8512h_link_led_set(struct Wed_phy *p_phy,
                                 int             phy_addr,
                                 int             led_idx){
    int      ret;
    uint16_t data         = 0, mask = 0;
    uint16_t link_led_reg = YT8512_EXTREG_LED0 + led_idx;

    if (p_phy == NULL) {
        return -WED_EINVAL;
    }

    data = YT8512_LED_BT_ON_EN | YT8512_LED_HT_ON_EN;

    if (link_led_reg == YT8512_EXTREG_LED0) {
        mask = YT8512_LED0_DIS_LED_AN_TRY;
    }
    mask |= YT8512_LED_TXACT_BLK_EN | YT8512_LED_RXACT_BLK_EN |
            YT8512_LED_BT_BLK_EN    | YT8512_LED_HT_BLK_EN    |
            YT8512_LED_COL_BLK_EN;
    data &= ~mask;

    ret = p_phy->p_opts->p_fn_mdio_write(p_phy->p_opts_arg, phy_addr, YT8512H_EXT_REG_OFFSET, link_led_reg);
    if (ret != 0) {
        return ret;
    }

    return p_phy->p_opts->p_fn_mdio_write(p_phy->p_opts_arg, phy_addr, YT8512H_EXT_REG_DATA, data);
}

/**
 * \brief PHY YT8512 激活灯设置
 *
 * @param p_phy    PHY 设备名字
 * @param phy_addr PHY 设备地址
 * @param led_idx  灯索引
 *
 * @return 成功返回 0
 */
int Wed_phy_yt8512h_active_led_set(struct Wed_phy *p_phy,
                                   int             phy_addr,
                                   int             led_idx){
    int      ret;
    uint16_t data        = 0, mask = 0;
    uint16_t act_led_reg = YT8512_EXTREG_LED0 + led_idx;

    if (p_phy == NULL) {
        return -WED_EINVAL;
    }

    data = YT8512_LED_ACT_BLK_IND | YT8512_LED_TXACT_BLK_EN |
                  YT8512_LED_RXACT_BLK_EN;

    if (act_led_reg == YT8512_EXTREG_LED0) {
        mask = YT8512_LED0_DIS_LED_AN_TRY;
    }
    mask |= YT8512_LED_BT_BLK_EN  | YT8512_LED_HT_BLK_EN |
            YT8512_LED_COL_BLK_EN;
    data &= ~mask;

    ret = p_phy->p_opts->p_fn_mdio_write(p_phy->p_opts_arg, phy_addr, YT8512H_EXT_REG_OFFSET, act_led_reg);
    if (ret != 0) {
        return ret;
    }

    return p_phy->p_opts->p_fn_mdio_write(p_phy->p_opts_arg, phy_addr, YT8512H_EXT_REG_DATA, data);
}

/**
 * \brief PHY YT8512 休眠控制
 *
 * @param p_phy    PHY 设备名字
 * @param phy_addr PHY 设备地址
 *
 * @return 成功返回 0
 */
int Wed_phy_yt8512h_sleep_control(struct Wed_phy *p_phy,
                                  int             phy_addr){
    int      ret;
    uint16_t data = 0;

    if (p_phy == NULL) {
        return -WED_EINVAL;
    }
    ret = p_phy->p_opts->p_fn_mdio_write(p_phy->p_opts_arg, phy_addr, YT8512H_EXT_REG_OFFSET, YT8512_EXTREG_SLEEP_CONTROL1);
    if (ret != 0) {
        return ret;
    }
    ret = p_phy->p_opts->p_fn_mdio_read(p_phy->p_opts_arg, phy_addr, YT8512H_EXT_REG_DATA, &data);
    if (ret != 0) {
        return ret;
    }

    data &= (~(0x1 << YT8512_EN_SLEEP_SW_BIT));

    ret = p_phy->p_opts->p_fn_mdio_write(p_phy->p_opts_arg, phy_addr, YT8512H_EXT_REG_OFFSET, YT8512_EXTREG_SLEEP_CONTROL1);
    if (ret != 0) {
        return ret;
    }
    return p_phy->p_opts->p_fn_mdio_write(p_phy->p_opts_arg, phy_addr, YT8512H_EXT_REG_DATA, data);
}

/**
 * \brief PHY YT8512 状态获取
 *
 * @param p_phy    PHY 设备名字
 * @param phy_addr PHY 设备地址
 *
 * @return 成功返回 0
 */
int Wed_phy_yt8512h_status_get(struct Wed_phy *p_phy,
                               int             phy_addr){
    int      ret;
    uint16_t data = 0;

    if (p_phy == NULL) {
        return -WED_EINVAL;
    }

    p_phy->is_link_up     = 0;
    p_phy->is_full_duplex = 0;

    ret = p_phy->p_opts->p_fn_mdio_read(p_phy->p_opts_arg, phy_addr, YT8512H_REG_SPEC_STATUS, &data);
    if (ret != 0) {
        return ret;
    }

    /* 链路处于 link up 且速率与双工模式解析成功 */
    if ((data & YT8512H_PHY_LINK_STATUS) &&
        (data & (1 << 11))) {
        p_phy->is_link_up = 1;
    }

    if ((data & YT8512H_PHY_LINK_SPEED) == YT8512H_PHY_LINK_SPEED_10) {
        p_phy->speed_mps = 10;
    } else if ((data & YT8512H_PHY_LINK_SPEED) == YT8512H_PHY_LINK_SPEED_100) {
        p_phy->speed_mps = 100;
    } else if ((data & YT8512H_PHY_LINK_SPEED) == YT8512H_PHY_LINK_SPEED_1000){
        p_phy->speed_mps = 1000;
    }

    if ((data & YT8512H_PHY_LINK_DUPLEX) == YT8512H_PHY_LINK_DUPLEX_FULL) {
        p_phy->is_full_duplex = 1;
    }

    return 0;
}
